﻿//这里引入了依赖注入相关的命名空间和您的项目命名空间。
using Microsoft.Extensions.DependencyInjection;
using netcore8.Inject;
using netcore8.InjectInterface;

using Microsoft.Extensions.DependencyInjection.Extensions;
using Autofac;
using netcore8.InjectInterfaceNoBuild;
using System.Reflection;

//顶级语句：这种新的结构不再需要显式定义 Main 方法
//这是基本的控制台输出，显示 "Hello, World!" 和命令行参数的数量。
Console.WriteLine("Hello, World!");
Console.WriteLine(args.Length);


#region 依赖注入-类注入-单例模式
{
    ////1、创建依赖注入，即创建IOC容器
    ////创建 ServiceCollection 对象，这是依赖注入容器。
    //ServiceCollection services = new ServiceCollection();

    ////2、注册类到IOC容器:涉及到的类都注册进去
    ////使用 AddSingleton 方法注册 ProductService 和 ProductRepository 类。这意味着这些类将以单例模式被创建和管理。
    //services.AddSingleton<ProductService>();
    //services.AddSingleton<ProductRepository>();

    ////调用 BuildServiceProvider() 来构建服务提供者。
    //var serviceProvider = services.BuildServiceProvider();

    ////使用 GetRequiredService<ProductService>() 来获取 ProductService 的实例。
    //ProductService productService = serviceProvider.GetRequiredService<ProductService>();    
    //productService.GetProduct();

    ///*
    //这段代码展示了如何设置和使用依赖注入容器。它创建了一个简单的 IoC（控制反转）容器，注册了一些服务，然后使用容器来解析和使用这些服务。     
    //需要注意的是，这个例子使用了单例模式（AddSingleton），这意味着 ProductService 和 ProductRepository 在整个应用程序生命周期中只会被创建一次。
    // */
}
#endregion

#region 依赖注入-类/接口注入-单例模式
//{
//    //1、创建依赖注入，即创建IOC容器
//    //创建 ServiceCollection 对象，这是依赖注入容器。
//    ServiceCollection services = new ServiceCollection();

//    //2、注册类到IOC容器:涉及到的类都注册进去    
//    /*
//        当有代码请求 IProduct2Service 类型的实例时，
//        提供一个 Product2Service 类的实例，
//        并且以单例模式管理这个实例（整个应用程序生命周期中只创建一次）     
//     */
//    services.AddSingleton<IProduct2Service,Product2Service>();
//    services.AddSingleton<IProduct2Repository,Product2Repository>();    

//    //调用 BuildServiceProvider() 来构建服务提供者。
//    var serviceProvider = services.BuildServiceProvider();

//    //使用 GetRequiredService<ProductService>() 来获取 ProductService 的实例。
//    //此处获取对象的时候，就会进入对应构造函数！
//    IProduct2Service productService = serviceProvider.GetRequiredService<IProduct2Service>();
//    productService.GetProduct();
//}
#endregion

#region 依赖注入-类/接口注入-单例模式-多实现类-循环多个注册实现
//{
//    //1、创建依赖注入，即创建IOC容器
//    //创建 ServiceCollection 对象，这是依赖注入容器。
//    ServiceCollection services = new ServiceCollection();

//    //2、注册类到IOC容器:涉及到的类都注册进去        
//    services.AddSingleton<IProduct2Service, Product2Service>();
//    services.AddSingleton<IProduct2Service, Product2CSService>();
//    services.AddSingleton<IProduct2Repository, Product2Repository>();

//    //调用 BuildServiceProvider() 来构建服务提供者。
//    var serviceProvider = services.BuildServiceProvider();

//    //使用 GetRequiredService<ProductService>() 来获取 ProductService 的实例。
//    //此处获取对象的时候，就会进入对应构造函数！
//    IProduct2Service productService = serviceProvider.GetRequiredService<IProduct2Service>();
//    productService.GetProduct();

//    var allServices = serviceProvider.GetServices<IProduct2Service>();
//    // 这会返回所有注册的 IProduct2Service 实现的集合
//    foreach (var service in allServices)
//    {
//        Console.WriteLine(service.GetHashCode());
//        service.GetProduct();
//    }
//}
#endregion

//#region 依赖注入-类/接口注入-AddTransient-多实现类
//{
//    //1、创建依赖注入，即创建IOC容器
//    //创建 ServiceCollection 对象，这是依赖注入容器。
//    ServiceCollection services = new ServiceCollection();

//    //2、注册类到IOC容器:涉及到的类都注册进去        
//    services.AddTransient<IProduct2Service, Product2Service>();
//    services.AddTransient<IProduct2Service, Product2CSService>();
//    services.AddTransient<IProduct2Repository, Product2Repository>();

//    //调用 BuildServiceProvider() 来构建服务提供者。
//    var serviceProvider = services.BuildServiceProvider();

//    //此处获取对象的时候，就会进入对应构造函数！
//    IProduct2Service productService = serviceProvider.GetRequiredService<IProduct2Service>();
//    productService.GetProduct();
//}
//#endregion

#region 依赖注入-类/接口注入-Scope-多实现类
//{
//    //1、创建依赖注入，即创建IOC容器
//    //创建 ServiceCollection 对象，这是依赖注入容器。
//    ServiceCollection services = new ServiceCollection();

//    //2、注册类到IOC容器:涉及到的类都注册进去        
//    services.AddScoped<IProduct2Service, Product2Service>();
//    services.AddScoped<IProduct2Service, Product2CSService>();
//    services.AddScoped<IProduct2Repository, Product2Repository>();

//    //调用 BuildServiceProvider() 来构建服务提供者。
//    var serviceProvider = services.BuildServiceProvider();

//    //创建和使用作用域：创建一个新的作用域。在 Web 应用中，通常每个请求都有自己的作用域。
//    //using 语句确保作用域在使用后被正确释放。
//    using (IServiceScope serviceScope = serviceProvider.CreateScope())
//    {
//        //此处获取对象的时候，就会进入对应构造函数！
//        IProduct2Service productService = serviceProvider.GetRequiredService<IProduct2Service>();
//        productService.GetProduct();
//    }
//}
#endregion



#region 依赖注入-类/接口注入-单例模式-多实现类-使用命名注册
//{
//    /*
//        如果您有多个命名注册，您可以在注册时使用不同的名称，并在获取服务时相应地调整类型检查。
//        另一种替代方法是使用第三方库如 Scrutor，它提供了更强大的依赖注入功能，包括更好的命名注册支持。     【Scrutor】
//     */
//    //1、创建依赖注入，即创建IOC容器
//    //创建 ServiceCollection 对象，这是依赖注入容器。
//    ServiceCollection services = new ServiceCollection();

//    ////2、注册类到IOC容器:涉及到的类都注册进去        报错！
//    //services.AddSingleton<IProduct2Service, Product2Service>("ServiceA");

//    //// 使用命名注册 Product2Service
//    //services.TryAddEnumerable(ServiceDescriptor.Singleton<IProduct2Service, Product2Service>("ServiceA"));

//    services.AddSingleton<IProduct2Service, Product2Service>();
//    services.AddSingleton<IProduct2Service, Product2CSService>();
//    services.AddSingleton<IProduct2Repository, Product2Repository>();

//    //调用 BuildServiceProvider() 来构建服务提供者。
//    var serviceProvider = services.BuildServiceProvider();

//    //使用 GetRequiredService<ProductService>() 来获取 ProductService 的实例。
//    //此处获取对象的时候，就会进入对应构造函数！
//    IProduct2Service productService = serviceProvider.GetRequiredService<IProduct2Service>();
//    productService.GetProduct();

//    var allServices = serviceProvider.GetServices<IProduct2Service>();
//    // 这会返回所有注册的 IProduct2Service 实现的集合
//    foreach (var service in allServices)
//    {
//        Console.WriteLine(service.GetHashCode());
//        service.GetProduct();
//    }    
//}
#endregion

#region 依赖注入-类/接口注入-单例模式-多实现类-使用工厂模式
//{
//    //1、创建依赖注入，即创建IOC容器
//    //创建 ServiceCollection 对象，这是依赖注入容器。
//    ServiceCollection services = new ServiceCollection();

//    //2、注册类到IOC容器:涉及到的类都注册进去        报错！ 
//    services.AddSingleton<IProduct2Service, Product2Service>();
//    services.AddSingleton<IProduct2Service, Product2CSService>();
//    services.AddSingleton<IProduct2Repository, Product2Repository>();

//    services.AddSingleton<Func<string, IProduct2Service>>(serviceProvider => key =>
//    {
//        switch (key)
//        {
//            case "A":
//                //return new Product2ServiceA();   运行报错！
//                return serviceProvider.GetRequiredService<Product2Service>();
//            case "B":
//                //return new Product2ServiceB();
//                return serviceProvider.GetRequiredService<Product2CSService>();
//            default:
//                throw new ArgumentException("Invalid key", nameof(key));
//        }
//    });

//    //调用 BuildServiceProvider() 来构建服务提供者。
//    var serviceProvider = services.BuildServiceProvider();

//    var factory = serviceProvider.GetRequiredService<Func<string, IProduct2Service>>();
//    var serviceA = factory("A");
//    serviceA.GetProduct();

//}
#endregion

/*
 
接口有多个实现类的情况： 当一个接口有多个实现类时，有几种处理方法： 
a) 注册默认实现：
services.AddSingleton<IProduct2Service, DefaultProduct2Service>();

b) 注册多个实现并使用命名注册：
services.AddSingleton<IProduct2Service, Product2ServiceA>();
services.AddSingleton<IProduct2Service, Product2ServiceB>();
services.AddSingleton<IProduct2Service, Product2ServiceC>();
然后在需要使用时：
var services = serviceProvider.GetServices<IProduct2Service>();
// 这会返回所有注册的 IProduct2Service 实现的集合

c) 使用命名注册（推荐）：
services.AddSingleton<IProduct2Service, Product2ServiceA>("ServiceA");
services.AddSingleton<IProduct2Service, Product2ServiceB>("ServiceB");
然后在需要使用时：
var serviceA = serviceProvider.GetRequiredService<IProduct2Service>("ServiceA");
var serviceB = serviceProvider.GetRequiredService<IProduct2Service>("ServiceB");

d) 使用工厂模式：
services.AddSingleton<Func<string, IProduct2Service>>(serviceProvider => key =>
{
    switch (key)
    {
        case "A":
            return new Product2ServiceA();
        case "B":
            return new Product2ServiceB();
        default:
            throw new ArgumentException("Invalid key", nameof(key));
    }
});
使用时：
var factory = serviceProvider.GetRequiredService<Func<string, IProduct2Service>>();
var serviceA = factory("A");
var serviceB = factory("B");



选择哪种方法取决于您的具体需求。如果您需要在运行时动态选择实现，工厂模式可能是最佳选择。如果您有固定数量的已知实现，命名注册可能更简单直接。
以上C,D验证失败！


1、使用 AddSingleton 会创建单例实例。    
 项目中：做缓存。无状态的服务接口
2、如果您需要每次请求都创建新实例，可以使用 AddTransient；
​ 项目中：状态的服务接口 每个接口中的Id都不一样的时候。存储业务Id的。
3、如果需要每个HTTP请求一个实例，可以使用 AddScoped（在Web应用中）。【事物提交】
 作用域生命周期 单例 +Transient 结合
 项目业务场景：1、数据库链接 2、数据库事务 3、request请求。httpcontext在一个请求类是唯一的。
​ 总结：Scope session。一个会话。一个sesssion 。

多实现注册：业务场景：写框架。多需求的时候。具体：实现用户注册。Cookie Session redis

 */


/*
Microsoft.Extensions.DependencyInjection

​ 缺陷：

​ 1、只能使用构造函数实现依赖注入。

​ 技术：Autofac 。使用属性依赖注入。

​ 2、无法实现批量注册

​ 3、无法实现对象过滤

​ 接口实现过滤

​ 特性实现过滤。(留给兄弟们去完成) 
 
 */



/*
Autofac 的优点：

更灵活的注册：Autofac 提供了多种注册方式，如按模块注册、按程序集注册等。
属性注入：除了构造函数注入，Autofac 还支持属性注入。
命名注册和检索：可以为同一接口注册多个实现，并通过名称区分。
模块化：可以将注册逻辑分散到多个模块中，提高代码组织性。
高级生命周期管理：除了 Transient、Scoped、Singleton，还支持更多生命周期选项。
延迟初始化：支持服务的延迟初始化，提高性能。
事件：支持在组件创建、激活等阶段触发事件。 
 */

#region 依赖注入-Autofac-依然构造函数生效
//{
//    // 1、创建ContainerBuilder
//    ContainerBuilder builder = new ContainerBuilder();
//    //注册接口和实现类到容器
//    /*
//     这里使用 RegisterType 方法注册具体类型。
//    .As<Interface>() 指定了这个类型应该被注册为哪个接口。
//    这种方式允许一个类型实现多个接口，并可以根据需要注册为不同的接口。
//     */
//    builder.RegisterType<Product2Service>().As<IProduct2Service>().PropertiesAutowired();
//    builder.RegisterType<Product2CSService>().As<IProduct2Service>().PropertiesAutowired();    
//    builder.RegisterType<Product2Repository>().As<IProduct2Repository>().PropertiesAutowired();

//    //2、构造容器
//    // 这步骤完成了 Autofac 容器的配置，返回一个可以解析服务的 IContainer。
//    var container = builder.Build();

//    //3、取对象 
//    //获取服务
//    using (var scope = container.BeginLifetimeScope()) {
//        //使用 Resolve 方法从容器中获取 IProduct3Service 的实例。
//        IProduct2Service product2Service = scope.Resolve<IProduct2Service>();
//        product2Service.GetProduct();
//    }
//}
#endregion


#region 依赖注入-Autofac-属性注入
//{
//    // 1、创建ContainerBuilder
//    ContainerBuilder builder = new ContainerBuilder();
//    //注册接口和实现类到容器
//    /*
//     这里使用 RegisterType 方法注册具体类型。
//    .As<Interface>() 指定了这个类型应该被注册为哪个接口。
//    这种方式允许一个类型实现多个接口，并可以根据需要注册为不同的接口。
//     */
//    builder.RegisterType<Product3Service>().As<IProduct3Service>().PropertiesAutowired();
//    builder.RegisterType<Product3CSService>().As<IProduct3Service>().PropertiesAutowired();
//    builder.RegisterType<Product3Repository>().As<IProduct3Repository>().PropertiesAutowired();

//    //2、构造容器
//    // 这步骤完成了 Autofac 容器的配置，返回一个可以解析服务的 IContainer。
//    var container = builder.Build();

//    //3、取对象 
//    //获取服务
//    using (var scope = container.BeginLifetimeScope())
//    {
//        //使用 Resolve 方法从容器中获取 IProduct3Service 的实例。
//        IProduct3Service product3Service = scope.Resolve<IProduct3Service>();
//        product3Service.GetProduct();
//    }
//}
#endregion

#region 依赖注入-Autofac-属性注入
{
    // 1、创建ContainerBuilder
    ContainerBuilder builder = new ContainerBuilder();

    //整个项目注册
    //注册当前程序集中的所有类型
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())//加载整个项目
                                                                  //实现过滤：过滤只注册实现了Inject接口的类型。只实现了此接口Inject的类型
                                                                  //GetInterfaces：获取所有接口实现
        .Where(t => t.GetInterfaces().Any(i => i == typeof(InjectRoot)))
        //只要有接口都实现注册
        .AsImplementedInterfaces()
        //PropertiesAutowired() 启用了属性自动注入，这意味着 Autofac 会尝试注入所有公共可写属性，即使没有特性标记。
        //开发属性依赖注入。启用属性注入，允许autofac自动注入标记了特定特性的属性
        .PropertiesAutowired();

    //2、构造容器
    // 这步骤完成了 Autofac 容器的配置，返回一个可以解析服务的 IContainer。
    var container = builder.Build();

    //3、取对象 
    //获取服务
    using (var scope = container.BeginLifetimeScope())
    {
        //使用 Resolve 方法从容器中获取 IProduct3Service 的实例。
        IProduct3Service product3Service = scope.Resolve<IProduct3Service>();
        product3Service.GetProduct();

        IUserService userService = scope.Resolve<IUserService>();
        userService.GetProduct("q13");
    }
}
#endregion


/*
todo: https://www.cnblogs.com/liang24/p/14541650.html 
 
 */
